package at.fhhagenberg.hydrac.java.sample.ast.codegen.builder;

import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;

public class ClassBuilder {

	private final String packageName;

	private final String className;

	private TypeDeclaration classObj;

	private final AST ast;

	private final CompilationUnit cu;

	private final AstBuilder astBuilder;

	public ClassBuilder(AstBuilder astBuilder, String packageName, String className) {
		ast = astBuilder.getAst();

		this.astBuilder = astBuilder;
		this.packageName = packageName;
		this.className = className;

		cu = ast.newCompilationUnit();

		init();
	}

	private void init() {
		// define package
		PackageDeclaration p1 = ast.newPackageDeclaration();
		p1.setName(astBuilder.newName(packageName));
		cu.setPackage(p1);

		// define class
		classObj = ast.newTypeDeclaration();
		classObj.setName(ast.newSimpleName(className));
		cu.types().add(classObj);

	}

	public ClassBuilder addImportStatement(Class<?> clazz) {
		return addImportStatement(clazz.getCanonicalName());
	}

	public ClassBuilder addImportStatement(String clazz) {
		ImportDeclaration id = ast.newImportDeclaration();
		id.setName(astBuilder.newName(clazz));
		cu.imports().add(id);

		return this;
	}

	void addMethodDecleration(MethodDeclaration methodDecl) {
		classObj.bodyDeclarations().add(methodDecl);
	}

	public MethodBuilder addMethod(String name) {
		MethodBuilder methodBuilder = new MethodBuilder(this, name);
		methodBuilder.addModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD);
		return methodBuilder;
	}

	public MethodBuilder addConstructor() {
		MethodBuilder methodBuilder = new MethodBuilder(this, className);
		methodBuilder.addModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD);
		methodBuilder.defineAsConstructure();
		return methodBuilder;
	}

	public MethodBuilder addMainMethod() {
		MethodBuilder methodBuilder = new MethodBuilder(this, "main");
		// --
		methodBuilder.addModifier(ModifierKeyword.PUBLIC_KEYWORD);
		methodBuilder.addModifier(ModifierKeyword.STATIC_KEYWORD);
		// --
		methodBuilder.setReturnType(PrimitiveType.VOID);
		// --
		methodBuilder.addParameterDeclaration("args", ast.newArrayType(ast.newSimpleType(ast.newSimpleName("String"))));

		return methodBuilder;
	}

	public void addFieldDeclaration(String name, Type type){
		VariableDeclarationFragment varDecl = ast.newVariableDeclarationFragment();
		varDecl.setName(ast.newSimpleName(name));
		FieldDeclaration fieldDecl = ast.newFieldDeclaration(varDecl);
		fieldDecl.setType(type);
		fieldDecl.modifiers().add(ast.newModifier(ModifierKeyword.PRIVATE_KEYWORD));
		classObj.bodyDeclarations().add(fieldDecl);
	}

	public AST getAst() {
		return ast;
	}

	@Override
	public String toString() {
		return cu.toString();
	}

}
